﻿using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;

using MyUtils.PInvoke.Consts;
using MyUtils.PInvoke.Structs;

using Brush = System.Windows.Media.Brush;
using Brushes = System.Windows.Media.Brushes;
using Size = System.Drawing.Size;

//- ReSharper disable UnusedMember.Local
// ReSharper disable InconsistentNaming

namespace MyUtils.PInvoke
{

	//[SuppressUnmanagedCodeSecurity]
	static class PInvoke
	{
		const string _user32Dll = "user32.dll";
		const string _dwmapiDll = "dwmapi.dll";
		const string _shell32Dll = "shell32.dll";
		const string _kernel32Dll = "kernel32.dll";

		// messages FROM the folder browser
		internal const int GWL_EXSTYLE = -20;
		internal const int WS_EX_LAYERED = 0x80000;
		internal const int LWA_ALPHA = 0x2;
		internal const int LWA_COLORKEY = 0x1;
		internal const int BFFM_INITIALIZED = 1;
		internal const int BFFM_SELCHANGED = 2;
		internal const int BFFM_VALIDATEFAILEDA = 3;
		internal const int BFFM_VALIDATEFAILEDW = 4;
		internal const int BFFM_IUNKNOWN = 5;
		
		// messages TO the folder browser
		internal const int BFFM_SETSTATUSTEXT = 0x464;
		internal const int BFFM_ENABLEOK = 0x465;
		internal const int BFFM_SETSELECTIONA = 0x466;
		internal const int BFFM_SETSELECTIONW = 0x467;

		#region HardLinks

		[DllImport(_shell32Dll)]
		internal static extern IntPtr SHBrowseForFolder(ref BrowseInfo lpBrowseInfo);

		[DllImport(_kernel32Dll, SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
		internal static extern bool CreateHardLink(string linkFileName, string existingFileName, IntPtr securityAttributes);

		internal static void CreateHardLink(string linkFileName, string existingFileName)
		{
			if (!CreateHardLink(linkFileName, existingFileName, default(IntPtr)))
			{
				throw new Exception(string.Format(@"Cannot create hard link here. Not supported or not enough rights.
ErrorCode = {0:X} ({0})", Marshal.GetLastWin32Error()));
			}
		}

		[DllImport(_kernel32Dll)]
		internal static extern bool GetFileInformationByHandle(IntPtr fileHandle, out ByHandleFileInformation fileInformation);

		#endregion

		[DllImport(_shell32Dll)]
		internal static extern int SHGetMalloc([Out] [MarshalAs(UnmanagedType.LPArray)] IMalloc[] ppMalloc);

		[DllImport(_shell32Dll, CharSet = CharSet.Auto)]
		public static extern bool SHGetPathFromIDList(IntPtr pidl, [MarshalAs(UnmanagedType.LPTStr, SizeConst = C.MAX_PATH)] StringBuilder pszPath);

		[DllImport(_shell32Dll)]
		internal static extern int SHGetSpecialFolderLocation(IntPtr hwnd, int csidl, ref IntPtr ppidl);

		[DllImport(_dwmapiDll, PreserveSig = false)]
		internal static extern void DwmEnableBlurBehindWindow(
			IntPtr hWnd, DWM_BLURBEHIND pBlurBehind);

		[DllImport(_dwmapiDll, PreserveSig = false)]
		internal static extern void DwmExtendFrameIntoClientArea(
			IntPtr hWnd, MARGINS pMargins);

		[DllImport(_dwmapiDll, PreserveSig = false)]
		internal static extern bool DwmIsCompositionEnabled();

		[DllImport(_dwmapiDll, PreserveSig = false)]
		internal static extern void DwmEnableComposition(bool enable);

		[DllImport(_dwmapiDll, PreserveSig = false)]
		internal static extern void DwmGetColorizationColor(
			out int pcrColorization,
			[MarshalAs(UnmanagedType.Bool)] out bool pfOpaqueBlend);

		[DllImport(_dwmapiDll, PreserveSig = false, SetLastError = true)]
		internal static extern IntPtr DwmRegisterThumbnail(
			IntPtr dest, IntPtr source);

		[DllImport(_dwmapiDll, PreserveSig = false)]
		internal static extern void DwmUnregisterThumbnail(IntPtr hThumbnail);

		[DllImport(_dwmapiDll, PreserveSig = false)]
		internal static extern void DwmUpdateThumbnailProperties(
			IntPtr hThumbnail, DWM_THUMBNAIL_PROPERTIES props);

		[DllImport(_dwmapiDll, PreserveSig = false)]
		internal static extern void DwmQueryThumbnailSourceSize(
			IntPtr hThumbnail, out Size size);

		[DllImport(_dwmapiDll, PreserveSig = false)]
		internal static extern void DwmExtendFrameIntoClientArea(IntPtr handle, ref MARGINS margins);

		internal const int WM_NCLBUTTONDOWN = 0xA1;
		internal const int HT_CAPTION = 0x2;

		[DllImport(_user32Dll, PreserveSig = false)]
		internal static extern void SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);

		[DllImport(_user32Dll)]
		internal static extern bool ReleaseCapture();

		internal static bool GlassEnabled
		{
			get { return Environment.OSVersion.Version.Major >= 6 && DwmIsCompositionEnabled(); }
		}

		[DllImport(_user32Dll, CharSet = CharSet.Auto)]
		internal static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, string lParam);

		[DllImport(_user32Dll, CharSet = CharSet.Auto)]
		internal static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, int lParam);

		[DllImport(_user32Dll, SetLastError = true)]
		internal static extern IntPtr FindWindowEx(HandleRef hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

		[DllImport(_user32Dll, SetLastError = true)]
		internal static extern Boolean SetWindowText(IntPtr hWnd, String text);

		internal const int BIF_DEFAULT = 0x0000;
		internal const int BIF_BROWSEFORCOMPUTER = 0x1000;
		internal const int BIF_BROWSEFORPRINTER = 0x2000;
		internal const int BIF_BROWSEINCLUDEFILES = 0x4000;
		internal const int BIF_BROWSEINCLUDEURLS = 0x0080;
		internal const int BIF_DONTGOBELOWDOMAIN = 0x0002;
		internal const int BIF_EDITBOX = 0x0010;
		internal const int BIF_NEWDIALOGSTYLE = 0x0040;
		internal const int BIF_NONEWFOLDERBUTTON = 0x0200;
		internal const int BIF_RETURNFSANCESTORS = 0x0008;
		internal const int BIF_RETURNONLYFSDIRS = 0x0001;
		internal const int BIF_SHAREABLE = 0x8000;
		internal const int BIF_STATUSTEXT = 0x0004;
		internal const int BIF_UAHINT = 0x0100;
		internal const int BIF_VALIDATE = 0x0020;
		internal const int BIF_NOTRANSLATETARGETS = 0x0400;
		//		[SuppressUnmanagedCodeSecurity]
		//		internal internal static class Shell32
		//		{
		// Methods
		//
		//		}
		//

		[Flags]
		public enum SHGFI : uint
		{
			/// <summary>get icon</summary>
			Icon = 0x000000100,
			/// <summary>get display name</summary>
			DisplayName = 0x000000200,
			/// <summary>get type name</summary>
			TypeName = 0x000000400,
			/// <summary>get attributes</summary>
			Attributes = 0x000000800,
			/// <summary>get icon location</summary>
			IconLocatin = 0x000001000,
			/// <summary>return exe type</summary>
			ExeType = 0x000002000,
			/// <summary>get system icon index</summary>
			SysIconIndex = 0x000004000,
			/// <summary>put a link overlay on icon</summary>
			LinkOverlay = 0x000008000,
			/// <summary>show icon in selected state</summary>
			Selected = 0x000010000,
			/// <summary>get only specified attributes</summary>
			Attr_Specified = 0x000020000,
			/// <summary>get large icon</summary>
			LargeIcon = 0x000000000,
			/// <summary>get small icon</summary>
			SmallIcon = 0x000000001,
			/// <summary>get open icon</summary>
			OpenIcon = 0x000000002,
			/// <summary>get shell size icon</summary>
			ShellIconize = 0x000000004,
			/// <summary>pszPath is a pidl</summary>
			PIDL = 0x000000008,
			/// <summary>use passed dwFileAttribute</summary>
			UseFileAttributes = 0x000000010,
			/// <summary>apply the appropriate overlays</summary>
			AddOverlays = 0x000000020,
			/// <summary>Get the index of the overlay in the upper 8 bits of the iIcon</summary>
			OverlayIndex = 0x000000040,
		}    

		//
//		internal const uint SHGFI_ICON = 0x100;
//		internal const uint SHGFI_LARGEICON = 0x0; // Large icon
//		internal const uint SHGFI_SMALLICON = 0x1; // Small icon
		internal const uint USEFILEATTRIBUTES = 0x000000010; // when the full path isn't available

		[DllImport(_shell32Dll, CharSet = CharSet.Auto)]
		internal static extern void SHGetFileInfo(string pszPath, uint dwFileAttributes, out SHFILEINFO psfi, uint cbSizeFileInfo, SHGFI uFlags);

		[DllImport("User32", PreserveSig=false)]
		internal static extern void DestroyIcon(IntPtr hIcon);

		[DllImport(_shell32Dll, CharSet = CharSet.Auto)]
		internal static extern int ExtractIconEx(string exeFileName, int iconIndex, ref IntPtr iconLarge, ref IntPtr iconSmall, int icons);

		internal static Icon GetSmallIcon(string fileName)
		{
			return GetIcon(fileName, false);
		}

		internal static Icon GetIcon(string fileName, bool large)
		{
			SHFILEINFO shinfo;
			SHGetFileInfo(fileName, 0, out shinfo, (uint)Marshal.SizeOf(typeof(SHFILEINFO)), SHGFI.Icon | (large ? SHGFI.LargeIcon : SHGFI.SmallIcon) /*| USEFILEATTRIBUTES*/);
			//The icon is returned in the hIcon member of the shinfo struct
			var icon = (Icon)Icon.FromHandle(shinfo.hIcon).Clone();
			DestroyIcon(shinfo.hIcon);
			return icon;
		}

		internal static Icon GetLargeIcon(string fileName)
		{
			return GetIcon(fileName, true);
		}

		internal const uint IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003; // Moiunt point or junction, see winnt.h
		internal const uint IO_REPARSE_TAG_SYMLINK = 0xA000000C; // SYMLINK or SYMLINKD (see http://wesnerm.blogs.com/net_undocumented/2006/10/index.html)
		internal const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002;
		internal const string SE_BACKUP_NAME = "SeBackupPrivilege";
		internal const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
		internal const uint FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
		internal const uint FILE_DEVICE_FILE_SYSTEM = 9;
		internal const uint FILE_ANY_ACCESS = 0;
		internal const uint METHOD_BUFFERED = 0;
		internal const int MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024;
		internal const uint TOKEN_ADJUST_PRIVILEGES = 0x0020;
		internal const int FSCTL_GET_REPARSE_POINT = 42;

		[DllImport(_kernel32Dll, ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
		[return: MarshalAs(UnmanagedType.Bool)]
		internal static extern bool DeviceIoControl(
			IntPtr hDevice,
			uint dwIoControlCode,
			IntPtr lpInBuffer,
			uint nInBufferSize,
			out REPARSE_DATA_BUFFER outBuffer,
			uint nOutBufferSize,
			out uint lpBytesReturned,
			IntPtr lpOverlapped);

		[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
		internal static extern IntPtr CreateFile(
			string fileName,
			[MarshalAs(UnmanagedType.U4)] FileAccess fileAccess,
			[MarshalAs(UnmanagedType.U4)] FileShare fileShare,
			int securityAttributes,
			[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
			uint flags,
			IntPtr template);

		[DllImport("advapi32.dll", SetLastError = true)]
		[return: MarshalAs(UnmanagedType.Bool)]
		internal static extern bool OpenProcessToken(IntPtr ProcessHandle,
		                                    UInt32 DesiredAccess, out IntPtr TokenHandle);

		[DllImport(_kernel32Dll)]
		internal static extern IntPtr GetCurrentProcess();

		[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
		[return: MarshalAs(UnmanagedType.Bool)]
		internal static extern bool LookupPrivilegeValue(string lpSystemName, string lpName,
		                                        out LUID lpLuid);

		[DllImport("advapi32.dll", SetLastError = true)]
		[return: MarshalAs(UnmanagedType.Bool)]
		internal static extern bool AdjustTokenPrivileges(IntPtr TokenHandle,
		                                         [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges,
		                                         ref TOKEN_PRIVILEGES NewState,
		                                         Int32 BufferLength,
		                                         //ref TOKEN_PRIVILEGES PreviousState, //					!! for some reason this won't accept null
		                                         IntPtr PreviousState,
		                                         IntPtr ReturnLength);

		[DllImport(_kernel32Dll, SetLastError = true)]
		[return: MarshalAs(UnmanagedType.Bool)]
		internal static extern bool CloseHandle(IntPtr hObject);

		[DllImport(_user32Dll)]
		internal static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);

		[DllImport(_user32Dll)]
		internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

		[DllImport(_user32Dll, SetLastError = false)]
		internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);

		internal static IMalloc GetSHMalloc()
		{
			var ppMalloc = new IMalloc[1];
			SHGetMalloc(ppMalloc);
			return ppMalloc[0];
		}
	}

	// This is the official version of the data buffer, see http://msdn2.microsoft.com/en-us/library/ms791514.aspx
	// not the one used at http://www.flexhex.com/docs/articles/hard-links.phtml
}